package com.gitee.loyo.utils;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.gitee.loyo.Request;
import com.gitee.loyo.config.ChargeProperties;
import com.gitee.loyo.err.RequestFailureException;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import okhttp3.*;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.lang.reflect.Type;
import java.net.SocketTimeoutException;
import java.util.Map;

@Slf4j
@Component
@RequiredArgsConstructor
public class OkHttpHelper {
    protected final MediaType MEDIA_TYPE = MediaType.parse("application/json;charset=utf-8");
    protected final ChargeProperties config;
    protected final OkHttpClient client;
    protected final ObjectMapper objectMapper;

    public Object post(String url, Request request, String token, Type type) throws IOException {
        okhttp3.Request.Builder requestBuilder = new okhttp3.Request.Builder().url(url);
        Map<String, String> headers = request.buildHeaders(token);
        if(headers != null && !headers.isEmpty()){
            headers.forEach((name, value) -> requestBuilder.addHeader(name, value));
        }
        Request<String> body = request.encryptAndSign(
            config.getDataSecretIV(),
            config.getDataSecret(),
            config.getSigSecret(),
            o -> objectMapper.writeValueAsString(o)
        );

        final RequestBody requestBody = RequestBody.create(
            MEDIA_TYPE,
            objectMapper.writeValueAsBytes(body)
        );
        requestBuilder.method("POST", requestBody);

        return  _post(requestBuilder, type, 0);
    }

    protected Object _post(okhttp3.Request.Builder requestBuilder, Type type, int count) throws IOException {
        okhttp3.Request request = requestBuilder.build();
        try{
            Response response = client.newCall(request).execute();
            if(response.code() != 200){
                throw new RequestFailureException(response);
            }
            ResponseBody responseBody = response.body();
            return objectMapper.readValue(responseBody.bytes(), objectMapper.getTypeFactory().constructType(type));
        }catch (SocketTimeoutException e){
            if(count < config.getRetry()){
                log.error("POST " + request.url().url().getPath() + ": timeout and retry");
                return _post(requestBuilder, type, count + 1);
            }else {
                throw e;
            }
        }
    }
}
